import type { AjaxResult } from '@/types'

interface PollingOptions<V = any> {
  /**
   * 重复次数
   * @description 0为无限重复
   * @default 0
   */
  repeat: number
  /**
   * 间隔时间
   * @description 单位毫秒
   * @default 3000
   */
  wait: number
  /**
   * 初始默认值
   */
  initialValue: V
  /**
   * 立即执行
   * 是否在定时器开始前立即执行一次
   * @default false
   */
  executeNow: boolean
}
/**
 * 轮询
 * @param request  [方法]
 * @param options [配置]
 * @returns [data,start]
 * @description 请求轮询使用 useRequestPolling
 * 使用查看 @/views/test1.vue文件
 */
export function usePolling<
  T extends (...args: any[]) => any = () => any,
  // eslint-disable-next-line
  R extends any = Awaited<ReturnType<T>>,
  P extends any[] = Parameters<T>,
>(request: T, options?: Partial<PollingOptions<R>>) {
  /** 用户配置重复次数 */
  const [repeat, setRepeat] = useNativeState(
    options?.repeat ?? 0,
  )
  /** 请求次数记录 */
  const [num, setNum] = useNativeState(0)
  /** 等待时间 */
  const [wait, setWait] = useNativeState(
    options?.wait ?? 3000,
  )
  /** 是否立即执行 */
  const [executeNow, setExecuteNow] = useNativeState(
    options?.executeNow ?? false,
  )
  let timeout: NodeJS.Timeout | null = null
  /** 接口返回数据 */
  const [data, setData] = useState<R | null>(
    options?.initialValue ?? null,
  )

  /**
   * 启动
   * @param params 请求参数
   * @param handleParams 请求参数处理器，将在每次请求前执行
   */
  const start = async <
    H extends (...args: P) => P | Promise<P>,
  >(
    ...args: P
  ) => {
    const handle = async () => {
      if (repeat.value && num.value === repeat.value) {
        end()
        return
      }
      args = handleParams
        ? await handleParams(...args)
        : args

      try {
        const res: R = await request(args)
        setData(res)
      }
      catch (e: any) {
        console.warn(
          `${request.name} error:${
            e?.message ?? e ?? '请求错误'
          }`,
        )
      }
      finally {
        if (!options?.repeat)
          // eslint-disable-next-line no-unsafe-finally
          return
        num.value++
      }
    }
    // executeNow.value && handle();
    let handleParams: H | null = null
    timeout = setInterval(handle, wait.value)

    /**
     * 可传入一个参数处理函数
     * 或者为当前配置项的重置对象
     * 或者传入true(或者不传) 表示当次启动将配置重置为usePolling 内的options配置项
     */
    return <
      I extends
      | H
      | true
      | Partial<Omit<PollingOptions<R>, 'initialValue'>>,
    >(
      callback?: I,
    ) => {
      if (typeof callback === 'function') {
        // 参数处理函数
        handleParams = callback as H
      }
      else if (
        (typeof callback === 'boolean' && callback)
        || typeof callback === 'undefined'
      ) {
        // 配置重置
        setExecuteNow(options?.executeNow ?? false)
        setWait(options?.wait ?? 3000)
        setRepeat(options?.repeat ?? 0)
        setNum(0)
      }
      else {
        // 重新配置
        if (typeof callback?.executeNow === 'boolean') {
          setExecuteNow(callback?.executeNow)
        }
        callback?.wait && setWait(callback?.wait)
        callback?.repeat && setRepeat(callback?.repeat)
      }
    }
  }
  const end = () => {
    timeout && clearInterval(timeout)
  }

  onBeforeUnmount(() => {
    end()
  })
  return [data, start, end] as const
}
/**
 * 请求轮询
 * @param request  [方法]
 * @param options [配置]
 * @returns [data,start]
 * 使用查看 @/views/test1.vue文件
 */
export function useRequestPolling<
  T extends (
    ...args: any[]
  ) => Promise<AjaxResult<any>> = () => Promise<
    AjaxResult<any>
  >,
  R extends AjaxResult<any> = Awaited<ReturnType<T>>,
  P extends any[] = Parameters<T>,
>(request: T, options?: Partial<PollingOptions<R['data']>>) {
  const [data, start, end] = usePolling<T, R, P>(
    request,
    options,
  )
  const _data = toRef(data.value?.data as R['data'])
  return [_data, start, end]
}
